//------------------------------------------------------------------------------
// Fichiers d'ent�te utilis�s
//------------------------------------------------------------------------------
#include "HysteresisThresholdOperator.hpp"
#include "Tools/Logger.hpp"
#include <iostream>

//------------------------------------------------------------------------------
// Définition de constantes
//------------------------------------------------------------------------------

namespace ImageAnalysis
{
	//----------------------------------------------------------------------
	// Constructeur
	//----------------------------------------------------------------------
	HysteresisThresholdOperator::HysteresisThresholdOperator( Gradiant* gradiant, BinaryImage* thresholdedImage, ThresholdFinder* finder ):
	currentGradiant(gradiant),
	currentThresholdedImage(thresholdedImage),
	thresholdFinder(finder)
	{

	}

	//----------------------------------------------------------------------
	// Destructeur
	//----------------------------------------------------------------------
	HysteresisThresholdOperator::~HysteresisThresholdOperator( )
	{

	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	void HysteresisThresholdOperator::Process( )
	{
		Region region( 0, 0, currentGradiant->GetWidth(), currentGradiant->GetHeight() );
		unsigned char* thresholds = thresholdFinder->GetTwoThresholds( &region, currentGradiant );		
		HysteresisTheshold( thresholds[0]>2?thresholds[0]:2, thresholds[1] );
				
		delete[] thresholds;
	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	void HysteresisThresholdOperator::HysteresisTheshold( int lowerThreshold, int upperThreshold )
	{
		// Pour tous les pixels de l'image on regarde si ils sont sup�ieur au
		// seuil haut. Si c'est le cas on le traite par r�ursivit�(m�hode
		// exploreNeighbor). Si ce n'est pas le cas alors on poursuit le
		// parcours des pixels.
		int imageSize = currentGradiant->GetWidth()*currentGradiant->GetHeight();
		unsigned char value;
		for( int pixelIndex=0; pixelIndex<imageSize; ++pixelIndex )
		{
			// On v�ifie que le pixel n'a pas d����trait�afin de ne pas
			// refaire le travail
			if( *currentThresholdedImage->GetPixel(pixelIndex) == BinaryImage::RESET_VALUE )
			{
				if( currentGradiant->GetGradiantNorm(pixelIndex) >= upperThreshold )
				{
					// Marquage du sommet test�comme appartenant au contour
					value = BinaryImage::WHITE_VALUE;
					currentThresholdedImage->SetPixel( pixelIndex, &value );
					
					// Exploration d'un nouveau contour
					ExploreNeighbor( pixelIndex, lowerThreshold );
				}
				else
				{
					// Marquage du sommet test�comme n'appartenant pas au contour
					value = BinaryImage::BLACK_VALUE;
					currentThresholdedImage->SetPixel( pixelIndex, &value );
				}
			}
		}	
	}

	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	void HysteresisThresholdOperator::ExploreNeighbor( int pixelIndex, int lowerThreshold )
	{
		// R�up�ation du voisinage du pixel courant
		Layer::PixelNeighborHood& neighborHood = currentGradiant->GetDirectPixelNeighborHood(pixelIndex);

		// Pour tous les pixels du voisinage on v�ifie si leur valeur est
		// sup�ieux au seuil bas (car on sait qu'ils sont connexes
		unsigned char value;
		for( int neighborIndex=0; neighborIndex < 9; ++neighborIndex )
		{
			int neighbor = neighborHood.index[neighborIndex];
			if( (neighbor != InvalidIndex) && (*currentThresholdedImage->GetPixel(neighbor) != BinaryImage::WHITE_VALUE) )
			{
				// Si le voisin courant �un niveau de gris sup�ieur au seuil
				// bas alors on l'ajoute au contour, sinon on le rejette.
				if( currentGradiant->GetGradiantNorm( neighbor ) >= lowerThreshold )
				{
					// Marquage du sommet test�comme appartenant au contour
					value = BinaryImage::WHITE_VALUE;
					currentThresholdedImage->SetPixel( neighbor, &value );
				
					// parcours du voisinage courant du point
					ExploreNeighbor( neighbor, lowerThreshold );
				}
				else
				{
					// Marquage du sommet test�comme n'appartenant pas au contour
					value = BinaryImage::BLACK_VALUE;
					currentThresholdedImage->SetPixel( neighbor, &value );
				}
			}
		}
	}
}


